package com.join.template.html.grammar;

import com.join.template.core.constant.Constant;
import com.join.template.core.constant.EntityType;
import com.join.template.core.factory.JoinFactory;
import com.join.template.core.grammar.config.GrammarField;
import com.join.template.core.grammar.generate.AbstractGenerateGrammar;
import com.join.template.core.grammar.generate.Generate;
import com.join.template.core.grammar.handle.Grammar;
import com.join.template.core.grammar.info.FieldGenerateInfo;
import com.join.template.core.grammar.info.GrammarInfo;
import com.join.template.core.util.ClassUtil;
import com.join.template.core.util.TemplateException;
import com.join.template.core.util.type.TypeInfo;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

/**
 * @author CAOYOU
 * @Title: Class2
 * @date 2019/10/2111:06
 */
public class ClassGenerate extends AbstractGenerateGrammar<Class, Field> implements Generate<Class, Field> {

    public ClassGenerate(JoinFactory joinFactory) {
        super(joinFactory);
    }

    @Override
    public Generate generate(String name, EntityType type, String describe, List<Field> childs) {
        try {
            GrammarInfo grammarInfo = this.grammarInfoClass.newInstance();
            grammarInfo.setName(name);
            grammarInfo.setType(type);
            grammarInfo.setDescribe(describe);
            this.createGrammarChild(grammarInfo, childs);
            this.grammarInfos.add(grammarInfo);

        } catch (InstantiationException e) {
            throw new TemplateException("语法生成失败", e);
        } catch (IllegalAccessException e) {
            throw new TemplateException("语法生成失败", e);
        }
        return this;
    }

    @Override
    public Generate generate(Class bean) {
        TypeInfo typeInfo = TypeInfo.get(bean);
        String name = typeInfo.getName();
        String describe = typeInfo.getName();
        EntityType type = EntityType.of(typeInfo.getType());
        GrammarField annotation = typeInfo.getAnnotation(GrammarField.class);
        if (annotation != null) {
            name = annotation.name();
            describe = annotation.describe();
            type = annotation.type();
        }
        generate(name, type, describe, Arrays.asList(bean.getDeclaredFields()));
        return this;
    }


    /**
     * 创建子集字段对应语法信息
     *
     * @param current
     * @param childs
     * @return void
     * @author CAOYOU/625954232@qq.com
     * @date 2019/8/21 16:17
     */
    private void createGrammarChild(GrammarInfo current, List<Field> childs) throws InstantiationException, IllegalAccessException {
        if (EntityType.Array == current.getType() || EntityType.Entity == current.getType()) {
            if (EntityType.Array == current.getType()) {
                createGrammarIndex(current);
            }
            for (Field item : childs) {
                if (item.getModifiers() == Modifier.STATIC || item.getModifiers() == Modifier.FINAL) {
                    continue;
                }
                if (this.getClass() == item.getType()
                        || Modifier.isStatic(item.getModifiers())
                        || Modifier.isFinal(item.getModifiers())) {
                    continue;
                }

                GrammarInfo grammarInfo = this.grammarInfoClass.newInstance();
                grammarInfo.setParentName(current.getName());
                grammarInfo.setParentType(current.getType());
                this.createGrammarInfo(grammarInfo, item);
                current.addChild(grammarInfo);
            }
        }
    }

    /**
     * 创建字段对应语法信息
     *
     * @param current
     * @param clazz
     * @return com.join.template.core.setGrammar.generate.GrammarInfo
     * @author CAOYOU/625954232@qq.com
     * @date 2019/8/21 16:16
     */
    private void createGrammarInfo(GrammarInfo current, Field clazz) throws IllegalAccessException, InstantiationException {
        TypeInfo typeInfo = TypeInfo.get(clazz);
        if (this.generateListener != null) {
            this.generateListener.onGenerate(current, typeInfo, this.generateConfig);
        }
        current.setName(typeInfo.getName());
        current.setType(EntityType.of(typeInfo.getType()));

        if (EntityType.Array == current.getType()) {
            current.setGrammarType(Constant.EXPR_LIST);
        } else {
            current.setGrammarType(Constant.EXPR_VAR);
        }

        Grammar grammar = joinFactory.getGrammar(current.getGrammarType());
        String example = grammar.getExample().genExample(current);
        current.setGrammar(example);

        Class clazz_ = null;
        if (Collection.class.isAssignableFrom(typeInfo.getType())) {
            clazz_ = ClassUtil.getClassGenricType(typeInfo.getGenericType());
        } else {
            clazz_ = typeInfo.getType();
        }
        if (clazz_ != null) {
            this.createGrammarChild(current, Arrays.asList(clazz_.getDeclaredFields()));
        }

    }
}
